home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 432_01 / ptmid3 / ptmidinp.c < prev    next >
C/C++ Source or Header  |  1994-07-05  |  15KB  |  534 lines

  1. /*
  2.  * ptmidinp.c: MIDI input module for for ptmid. Reads a MIDI file and
  3.  * creates a structure representing it.
  4.  *
  5.  * Author: Andrew Scott  (c)opyright 1994
  6.  *
  7.  * Date: 17/11/1993 ver 0.0
  8.  *       8/1/1994   ver 0.1
  9.  *       11/2/1994  ver 0.2
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <io.h>
  15. #include <fcntl.h>
  16. #include <string.h>
  17. #include "ptmid.h"
  18.  
  19. #define BUFSIZ 512
  20.  
  21. #define ODD(x) (x & 1)
  22.  
  23. typedef unsigned long VLQ; /** VLQ is a variable length quantity **/
  24.  
  25. typedef struct { /** RF is a record of a file **/
  26.   int fd, ib;
  27.     unsigned char rgb[BUFSIZ];
  28. } RF;
  29.  
  30. int rgbPatch[16], wDivision, wBendsen = 2, wModwheel = 0;
  31. unsigned wQuant;
  32. NRL *rgpnrl[16][128];
  33. Tune *ptuneMain, *ptuneCurr;
  34. RF *prf;
  35.  
  36. /*
  37.  * Init: Yes.. you guessed it. Initializes variables and stuff.
  38.  *
  39.  * date: 30/6/1994 - added 16 NRL array init
  40.  */
  41. static void Init(void)
  42. {
  43.   int i, j;
  44.  
  45.   for (i = 16; i--; ) { /** Clear current instrument array **/
  46.         rgbPatch[i] = 0;
  47.     for (j = 128; j--; ) /** Clear hanging-note arrays **/
  48.       rgpnrl[i][j] = NULL;
  49.   }
  50. }
  51.  
  52. /*
  53.  * ChGetFd: Given a file, returns next character from it.
  54.  */
  55. int ChGetFd(int fd)
  56. {
  57.     unsigned char b;
  58.  
  59.     if (read(fd, &b, 1) < 1)
  60.         return EOF;
  61.     return b;
  62. }
  63.  
  64. /*
  65.  * ChGetIrf: Given an index, returns next character from corresponding
  66.  * file record.
  67.  */
  68. unsigned char ChGetIrf(unsigned irf)
  69. {
  70.     if (prf[irf].ib == BUFSIZ) {
  71.         if (read(prf[irf].fd, prf[irf].rgb, BUFSIZ) == -1) {
  72.             ERROR;
  73.             exit(1);
  74.         }
  75.         prf[irf].ib = 1;
  76.         return prf[irf].rgb[0];
  77.     }
  78.     return prf[irf].rgb[prf[irf].ib++];
  79. }
  80.  
  81. /*
  82.  * SkipIrf: Given an index, skips a given number of bytes forward in
  83.  * that file record.
  84.  *
  85.  * date: 4/7/1994 - fixed longstanding bug: wouldn't read in new buffer
  86.  */
  87. void SkipIrf(unsigned irf, long cb)
  88. {
  89.   if (BUFSIZ - prf[irf].ib >= cb)
  90.     prf[irf].ib += (int) cb;
  91.     else {
  92.         cb -= BUFSIZ - prf[irf].ib;
  93.     if (lseek(prf[irf].fd, cb, SEEK_CUR) == -1) {
  94.             ERROR;
  95.             exit(1);
  96.         }
  97.     prf[irf].ib = BUFSIZ;
  98.     }
  99. }
  100.  
  101. /*
  102.  * ValidquantSz: Takes a lower-case string and checks to see if it is a
  103.  * legal quantize fraction. If not, zero is returned, else value of
  104.  * string is returned (+1 if a triplet case).
  105.  */
  106. int ValidquantSz(Sz szQuant)
  107. {
  108.     int bFrac;
  109.     Sz szEnd;
  110.  
  111.   if ((bFrac = (int) strtol(szQuant, &szEnd, 10))) /** If a number **/
  112.         if ('t' == *szEnd || 'T' == *szEnd) /** possibly followed by a 't' **/
  113.             bFrac++;
  114.     return bFrac; /** return valid **/
  115. }
  116.  
  117. /*
  118.  * VlqFromFd: Reads bytes from given file until a variable length
  119.  * quantity is decoded. Returns that vlq.
  120.  */
  121. VLQ VlqFromFd(int fd)
  122. {
  123.     VLQ vlqRead = 0;
  124.     unsigned char b = 0;
  125.  
  126.     while (read(fd, &b, 1) == 1 && (b & 0x80))
  127.         vlqRead = (vlqRead << 7) | (b & 0x7F);
  128.     return (vlqRead << 7) | b;
  129. }
  130.  
  131. /*
  132.  * VlqFromIrf: Reads bytes from file corresponding to given index until
  133.  * a variable length quantity is decoded. Returns that vlq.
  134.  */
  135. VLQ VlqFromIrf(unsigned irf)
  136. {
  137.     VLQ vlqRead = 0;
  138.     unsigned char b = 0;
  139.  
  140.     while ((b = ChGetIrf(irf)) & 0x80)
  141.         vlqRead = (vlqRead << 7) | (b & 0x7F);
  142.     return (vlqRead << 7) | b;
  143. }
  144.  
  145. /*
  146.  * LongFromFd: Reads number of bytes from Fd until number is in.
  147.  */
  148. unsigned long LongFromFd(int fd, unsigned cb)
  149. {
  150.     unsigned char rgb[4];
  151.     unsigned long longT = 0;
  152.     unsigned ib = 0;
  153.  
  154.     read(fd, rgb, cb);
  155.     for (; ib < cb; ib++)
  156.         longT = (longT << 8) + rgb[ib];
  157.     return longT;
  158. }
  159.  
  160. /*
  161.  * Addnote: Given channel, pitch, instrument, and volume will add that
  162.  * note to the array of playing notes.
  163.  *
  164.  * date: 30/6/1994 - added chan as well as pfx init
  165.  */
  166. void Addnote(int chan, int pitch, int inst, int vol)
  167. {
  168.     NRL *pnrlT;
  169.  
  170.   if (0 > pitch || 127 < pitch || 0 > chan || 15 < chan)
  171.         return;
  172.     pnrlT = (NRL *) malloc(sizeof(NRL)); /** Allocate space **/
  173.   pnrlT->pnrl = rgpnrl[chan][pitch];
  174.   rgpnrl[chan][pitch] = pnrlT; /** Attach to front of list in array **/
  175.     pnrlT->inst = inst;
  176.     pnrlT->vol = vol;
  177.   pnrlT->pfxTail = NULL;
  178.     pnrlT->ptuneNow = ptuneCurr;
  179. }
  180.  
  181. /*
  182.  * PeiRequestPtune: Returns a pointer to a new event structure at the
  183.  * position in the tune specified.
  184.  */
  185. EI *PeiRequestPtune(Tune *ptune)
  186. {
  187.     EI *pei;
  188.  
  189.     pei = (EI *) malloc(sizeof(EI)); /** Allocate space for event **/
  190.   pei->pei = ptune->pei;
  191.   ptune->pei = pei; /** Attach to front of event list at tune position **/
  192.     return pei;
  193. }
  194.  
  195. /*
  196.  * Endnote: Given a pitch and instrument, will remove a note from array
  197.  * of playing notes and store it as an event in the tune.
  198.  *
  199.  * date: 30/6/1994 - added support for effects, 16 chans, min. perc. durat.
  200.  */
  201. void Endnote(int chan, int pitch, int inst)
  202. {
  203.   NRL *pnrlT, *pnrlOld = NULL;
  204.     unsigned long durat;
  205.     EI *peiT;
  206.  
  207.   if (0 > pitch || 127 < pitch || 0 > chan || 15 < chan)
  208.         return;
  209.   for (pnrlT = rgpnrl[chan][pitch]; NULL != pnrlT && pnrlT->inst != inst; ) {
  210.         pnrlOld = pnrlT;
  211.         pnrlT = pnrlT->pnrl;
  212.     } /** Find instrument in hanging-note array **/
  213.     if (NULL == pnrlT)
  214.         return;
  215.  
  216.   durat = ptuneCurr->count - pnrlT->ptuneNow->count; /** Calc. duration **/
  217.   if (0 > inst && wDivision / 2 > durat)
  218.     durat = wDivision / 2; /** Percussion sounds have a min. duration **/
  219.   if (durat < wQuant)
  220.     durat = wQuant; /** All sounds have a min. duration **/
  221.  
  222.   peiT = PeiRequestPtune(pnrlT->ptuneNow); /** Get an event **/
  223.   peiT->effect = durat;
  224.   peiT->inst = inst; /** Store the note in it **/
  225.   peiT->pitch = pitch;
  226.   peiT->vol = pnrlT->vol;
  227.   peiT->pfxTail = pnrlT->pfxTail;
  228.  
  229.   if (NULL == pnrlOld) /** Remove note from hanging-note array **/
  230.     rgpnrl[chan][pitch] = pnrlT->pnrl;
  231.     else
  232.         pnrlOld->pnrl = pnrlT->pnrl;
  233.     free(pnrlT);
  234. }
  235.  
  236. /*
  237.  * VlqInterpIrf: Reads a file pointer and gathers all notes at this
  238.  * instant, storing them on the note stack. Returns ticks until next
  239.  * collection of notes. A running status of current channel is maintained.
  240.  *
  241.  * date: 30/6/1994 - added effect support
  242.  */
  243. VLQ VlqInterpIrf(unsigned irf, unsigned *pbStat)
  244. {
  245.     unsigned bEvent;
  246.     VLQ vlqT;
  247.   FX *pfx;
  248.  
  249.     do { /** Loop.. **/
  250.         bEvent = ChGetIrf(irf); /** Get first data byte **/
  251.         if (0x80 <= bEvent && 0xEF >= bEvent) { /** If a command **/
  252.             *pbStat = bEvent; /** update running-status byte **/
  253.             bEvent = ChGetIrf(irf); /** and get next data byte **/
  254.         }
  255.         if (0xF0 == bEvent || 0xF7 == bEvent) /** If a sys-exclusive message **/
  256.             SkipIrf(irf, VlqFromIrf(irf)); /** skip it **/
  257.         else if (0xFF == bEvent) { /** Else if a meta event **/
  258.             bEvent = ChGetIrf(irf); /** get type of event **/
  259.             vlqT = VlqFromIrf(irf); /** and length **/
  260.             if (0x2F == bEvent) { /*** If termination event ***/
  261.                 close(prf[irf].fd); /*** close handle ***/
  262.                 prf[irf].fd = -1;
  263.                 vlqT = 0;
  264.                 break; /*** and terminate ***/
  265.             }
  266.             if (0x51 == bEvent) { /*** Else if tempo event ***/
  267.                 unsigned long t;
  268.                 EI *pei;
  269.  
  270.                 t = (unsigned long) ChGetIrf(irf) << 16; /*** get value ***/
  271.                 t += (unsigned long) ChGetIrf(irf) << 8;
  272.                 t += ChGetIrf(irf);
  273.                 pei = PeiRequestPtune(ptuneCurr);
  274.                 pei->effect = 60000000L / wQuant * wDivision / t; /*** and convert ***/
  275.         pei->pitch = -1;
  276.             } else
  277.                 SkipIrf(irf, vlqT); /*** Else skip event ***/
  278.         } else
  279.             switch (*pbStat & 0xF0) { /** Else must be a midi event.. **/
  280.                 case 0x80:
  281.                 case 0x90: { /** Note on/off **/
  282.                     unsigned bVol, bChan;
  283.  
  284.                     bVol = ChGetIrf(irf);
  285.                     bChan = *pbStat & 0x0F;
  286.                     if (0 < bVol && 0x90 <= *pbStat)
  287.                         if (bChan != bDrumch)
  288.               Addnote(bChan, bEvent, rgbPatch[bChan], bVol);
  289.                         else
  290.               Addnote(bChan, 0, -1 - bEvent, bVol);
  291.                     else
  292.                         if (bChan != bDrumch)
  293.               Endnote(bChan, bEvent, rgbPatch[bChan]);
  294.                         else
  295.               Endnote(bChan, 0, -1 - bEvent);
  296.                     break;
  297.                 }
  298.         case 0xA0: { /** Polyphonic Key Pressure **/
  299.           NRL *pnrlT;
  300.           unsigned bChan;
  301.  
  302.           bChan = *pbStat & 0x0F;
  303.           pnrlT = rgpnrl[bChan][bEvent];
  304.           while (NULL != pnrlT && pnrlT->inst != rgbPatch[bChan])
  305.             pnrlT = pnrlT->pnrl;
  306.           if (NULL != pnrlT) {
  307.             pfx = (FX *) malloc(sizeof(FX));
  308.